﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureVariableSectionWall.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpGradientHeightParameterUpdater.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "IDocument.h"
#include "IElementModelShape.h"
#include "IElementParameters.h"
#include "IElementPosition.h"
#include "IElementStatus.h"
#include "IExternalDataComponent.h"
#include "IFamily.h"
#include "IInstance.h"
#include "IInstanceType.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IParameterOverride.h"
#include "IPositionCurve2d.h"
#include "IRegenerator.h"
#include "LevelUtils.h"
#include "StructureInstanceLevelUtils.h"
#include "StructureWallInput.h"
#include "StructureWallParametersCustomizer.h"
#include "StructureWallPositionPoints.h"
#include "IPositionTwoAssociatedPlanesWithFourOffsets.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace gcmp
{
    class StructWallBuiltInParameterOverrideBase : public IParameterOverride
    {
        DEFINE_CAST_DERIVED(StructWallBuiltInParameterOverrideBase, gcmp::IParameterOverride)
    public:
        virtual UniIdentity GetUniIdentity() const override { return UniIdentity::InvalidUid; }
        virtual bool ShouldOverrideIsModifiable() const override { return false; }
        virtual bool IsModifiable() const override
        {
            return true;
        }

        virtual bool ShouldOverrideIsUserVisible() const override { return false; }
        virtual bool IsUserVisible() const override
        {
            return true;
        }

        virtual bool ShouldOverrideGetName() const override { return false; }
        virtual std::wstring GetName() const override
        {
            return L"";
        }

        virtual bool ShouldOverrideGetValidator() const override { return false; }
        virtual const IParameterValidator * GetValidator() const override
        {
            return nullptr;
        }

        virtual IElement* GetOwnerElement() override { return nullptr; }
        virtual const IElement* GetOwnerElement() const override { return nullptr; }
        virtual bool SetOwnerElement(IElement* pElement) override { return true; }
    };

    /// \brief 结构墙的 起点高度 参数定制
    ///
    /// 只有变截面墙有这个参数，普通剪力墙没有。所以没有进一步区分。
    class StructureWallStartHeightBuiltInParameterOverride : public NdbObjectSchematic, public StructWallBuiltInParameterOverrideBase
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, StructureWallStartHeightBuiltInParameterOverride, gcmp::NdbObjectSchematic, 7B70D5FD - 691F - 470B - 8835 - D98134C5B7DB, gmstructure, gcmp::StructWallBuiltInParameterOverrideBase)
        DBOBJECT_DATA_END

    public:
        virtual UniIdentity GetUniIdentity() const override
        {
            return PARAMETER_UID(StartHeightBuiltInParameter);
        }
        virtual bool ShouldOverrideGetName() const override { return true; }
        virtual std::wstring GetName() const override
        {
            return L"起点墙高";
        }

    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }
    };

    DBOBJECT_DATA_DEFINE(StructureWallStartHeightBuiltInParameterOverride)
    {
    }

    /// \brief 结构墙的 终点高度 参数定制
    ///
    /// 只有变截面墙有这个参数，普通剪力墙没有。所以没有进一步区分。
    class StructureWallEndHeightBuiltInParameterOverride : public NdbObjectSchematic, public StructWallBuiltInParameterOverrideBase
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, StructureWallEndHeightBuiltInParameterOverride, gcmp::NdbObjectSchematic, A06AF1BC - 4182 - 4C12 - AAE6 - C7955D9647EC, gmstructure, gcmp::StructWallBuiltInParameterOverrideBase)
        DBOBJECT_DATA_END

    public:
        virtual UniIdentity GetUniIdentity() const override
        {
            return PARAMETER_UID(EndHeightBuiltInParameter);
        }
        virtual bool ShouldOverrideGetName() const override { return true; }
        virtual std::wstring GetName() const override
        {
            return L"终点墙高";
        }

    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }
    };

    DBOBJECT_DATA_DEFINE(StructureWallEndHeightBuiltInParameterOverride)
    {
    }
}

bool StructureVariableSectionWall::CustomizeParameters()
{
    IElement * pOwnerElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnerElement, L"GetOwnerElement()返回空指针？",L"GDMPLab",L"2024-03-30");
    IElementParameters * pElementParameters = pOwnerElement->GetElementParameters();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementParameters, L"pOwnerElement->GetElementParameters()返回空指针？",L"GDMPLab",L"2024-03-30");

    bool res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(StructureWallStartHeightBuiltInParameterOverride));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置起点高度参数定制器失败？",L"GDMPLab",L"2024-03-30");

    res = pElementParameters->AddIndividualParameterOverride(NEW_AS_OWNER_PTR(StructureWallEndHeightBuiltInParameterOverride));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(res, L"设置终点高度参数定制器失败？",L"GDMPLab",L"2024-03-30");
    return true;
}


DEFINE_STRUCTURE_INSTANCE_BASE_DATA_METHODS(StructureVariableSectionWall, BaseData);

DBOBJECT_DATA_DEFINE(StructureVariableSectionWall)
{

}

StructureVariableSectionWall* StructureVariableSectionWall::Create(const StructureWallInput *pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = nullptr;
    if (pInput->PositionType == ElementInputPositionType::Line)
    {
        pInstance = StructureVariableSectionWall::CreateStraightVariableSectionWall(pInput);
    }

    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    StructureVariableSectionWall* pBasicBeam = StructureVariableSectionWall::Get(pInstance);

    //自定义参数行为
    pBasicBeam->CustomizeParameters();
    return pBasicBeam;
}

const StructureVariableSectionWall* StructureVariableSectionWall::Get(const IInstance *pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    if (const IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        const IExternalData* pData = pExternalDataComponent->FindExternalData(StructureVariableSectionWall::GetStaticClassSchema()->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");

        return quick_cast<StructureVariableSectionWall>(pData);
    }
    return nullptr;
}

StructureVariableSectionWall* StructureVariableSectionWall::Get(IInstance *pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        IExternalData* pData = pExternalDataComponent->FindExternalData(StructureVariableSectionWall::GetStaticClassSchema()->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");

        return quick_cast<StructureVariableSectionWall>(pData);
    }
    return nullptr;
}

IInstance* StructureVariableSectionWall::CreateStraightVariableSectionWall(const StructureWallInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstanceType* pInstanceType = quick_cast<IInstanceType>(pDoc->GetElement(pInput->InstanceTypeId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstanceType, L"pInstanceType为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = pInstanceType->CreateInstance(L"墙实例", false, pInput->CreationOption, pInput->IsCreateGeometryRelationshipComponent);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    //设置实例外部自定义数据
    StructureVariableSectionWall* pWall = StructureVariableSectionWall::RegisterExternalData(pInstance, pInput);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWall, L"pBeam为空",L"GDMPLab",L"2024-03-30");

    //设置墙实例定位参数
    bool bOk = IElementPosition::CreateCurve2dOnTwoAssociatedPlanesWithFourOffsetsPositionBehavior(pInstance
        , pInput->AssociatedPlaneId, pInput->PositionPoints, pInput->TopAssociatedPlaneId);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"创建定位失败",L"GDMPLab",L"2024-03-30");


    //设置墙高内置参数更新行为
    IElementPosition* posBehavior = pInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"无效posBehavior",L"GDMPLab",L"2024-03-30");
    
    IPositionTwoAssociatedPlanesWithFourOffsets* pPlanes 
        = dynamic_cast<IPositionTwoAssociatedPlanesWithFourOffsets*>(posBehavior->GetPositionAssociatedPlane());
    if (pPlanes)
    {
        double dVal = pPlanes->GetTopOffset();
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(!IPositionAssociatedPlane::SetTopPlaneHeightOffset(pInstance, dVal), L"设置无效",L"GDMPLab",L"2024-03-30");
        IPositionAssociatedPlane::GetTopPlaneHeightOffset(pInstance, dVal);
        pPlanes->SetTopOffset(dVal);
    }


    OwnerPtr<IInstanceFamilyParametersUpdater> opParametersUpdater = NEW_AS_OWNER_PTR(GbmpGradientHeightParameterUpdater);
    posBehavior->SetParametersUpdater(TransferOwnership(opParametersUpdater));

    //设置墙高预设参数
    {
        OwnerPtr<IParameter> paramWallStartHeight = pInstance->GetElementParameters()->GetParameterByUid(PARAMETER_UID(StartHeightBuiltInParameter));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(paramWallStartHeight), L"paramWallHeight无效",L"GDMPLab",L"2024-03-30");
        paramWallStartHeight->SetValueAsDouble(pInput->StartHeight);
        pInstance->GetElementParameters()->SetParameter(paramWallStartHeight.get());

        OwnerPtr<IParameter> paramWallEndHeight = pInstance->GetElementParameters()->GetParameterByUid(PARAMETER_UID(EndHeightBuiltInParameter));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(paramWallEndHeight), L"paramWallHeight无效",L"GDMPLab",L"2024-03-30");
        paramWallEndHeight->SetValueAsDouble(pInput->EndHeight);
        pInstance->GetElementParameters()->SetParameter(paramWallEndHeight.get());
    }

    //设置起终点底部偏移预设参数
    {
        OwnerPtr<IParameter> paramWallStartOffest = pInstance->GetElementParameters()->GetParameterByUid(PARAMETER_UID(StartBottomAssociatedLevelOffsetBuiltInParameter));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(paramWallStartOffest), L"paramWallStartOffest无效",L"GDMPLab",L"2024-03-30");
        paramWallStartOffest->SetValueAsDouble(pInput->StartOffset);
        pInstance->GetElementParameters()->SetParameter(paramWallStartOffest.get());

        OwnerPtr<IParameter> paramWallEndOffest = pInstance->GetElementParameters()->GetParameterByUid(PARAMETER_UID(EndBottomAssociatedLevelOffsetBuiltInParameter));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(paramWallEndOffest), L"paramWallEndOffest无效",L"GDMPLab",L"2024-03-30");
        paramWallEndOffest->SetValueAsDouble(pInput->EndOffset);
        pInstance->GetElementParameters()->SetParameter(paramWallEndOffest.get());
    }

    //设置控制点行为
    pInstance->SetPositionPoints(NEW_AS_OWNER_PTR(StructureWallPositionPoints, pInstance, PARAMETER_UID(LineFamilyPositionCurveSideBuiltInParameter), PARAMETER_UID(CoreThicknessBuiltInParameter)));

    //设置实例所属楼层信息
    ElementId associatedPlaneId = pInput->AssociatedPlaneId;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(associatedPlaneId.IsValid(), L"associatedPlaneId无效",L"GDMPLab",L"2024-03-30");

    const ILevel* pStoreyLevel = nullptr;
    if (pInput->StoreyId.IsValid())
    {
        pStoreyLevel = LevelUtils::GetLevelById(pDoc, pInput->StoreyId);
    }
    else
    {
        pStoreyLevel = StructureInstanceLevelUtils::GetWallStoreyLevelFromPositioningLevel(pDoc, associatedPlaneId);
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStoreyLevel, L"pStoreyLevel为空",L"GDMPLab",L"2024-03-30");

    bOk = StructureInstanceLevelUtils::CreateInstanceStoreyLevel(pInstance, pStoreyLevel);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"SetBeamStoreyLevel失败",L"GDMPLab",L"2024-03-30");

    if (pInstance->GetElementParameters())
    {
        OwnerPtr<IElementParametersCustomizer> opNewCustomizer = 
            NEW_AS_OWNER_PTR(StructureWallParametersCustomizer, pInstance);
        GmStructureDefaultElementParametersCustomizer::SetElementParametersCustomizer(
            pInstance, TransferOwnership(opNewCustomizer));
    }

    const IPositionCurve2d* pPosCurve2d = dynamic_cast<const IPositionCurve2d*>(posBehavior->GetPositionGeometry());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPosCurve2d, L"pPosCurve2d为空",L"GDMPLab",L"2024-03-30");
    bOk = pInstance->SetCoordinateSystemsByCurve(pPosCurve2d->GetBaseCurve());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"SetCoordinateSystemsByCurve失败",L"GDMPLab",L"2024-03-30");

    IElementStatus* pStatus = pInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(pInput->Visible);

    bOk = pDoc->GetRegenerator()->RegenerateElement(pInstance->GetElementId());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"RegenerateElement失败",L"GDMPLab",L"2024-03-30");

    return pInstance;
}

StructureVariableSectionWall* StructureVariableSectionWall::RegisterExternalData(IInstance* pInstance, const StructureWallInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructureVariableSectionWall> opWall = NEW_AS_OWNER_PTR(StructureVariableSectionWall);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opWall, L"opBasicBeam为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructureWall> opBaseData = StructureWall::Create(pInstance, pInput);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opBaseData, L"opBaseData为空",L"GDMPLab",L"2024-03-30");
    opWall->SetBaseData__(TransferOwnership(opBaseData));

    StructureVariableSectionWall* pVariableSectionWall = opWall.get();
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        pExternalDataComponent->RegisterExternalData(StructureVariableSectionWall::GetStaticClassSchema()->GetName(), TransferOwnership(opWall));
    }
    return pVariableSectionWall;
}


void StructureVariableSectionWall::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    GetBaseDataFW__()->UpdateForWeakParentDeletion(deletedElementIds);
}
void StructureVariableSectionWall::ReportParents(IElementParentReporter& reporter) const
{
    GetBaseData__()->ReportParents(reporter);
}

void StructureVariableSectionWall::GetCalculators(ICalculatorCollection * calculators) const
{
    GetBaseData__()->GetCalculators(calculators);
}

void StructureVariableSectionWall::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    GetBaseData__()->ReportParameterDefinitions(pParamDefIds);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefIds, L"pParamDefIds为空",L"GDMPLab",L"2024-03-30");

}

OwnerPtr<IParameter> StructureVariableSectionWall::GetNativeParameter(int paramDefId) const
{
    OwnerPtr<IParameter> param = GetBaseData__()->GetNativeParameter(paramDefId);
    if (IParameter::IsValidParameter(param))
        return param;

    return nullptr;
}

bool StructureVariableSectionWall::SetNativeParameter(const IParameter *param, std::wstring* errorMsg/* = nullptr*/)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (GetBaseDataFW__()->SetNativeParameter(param, errorMsg))
        return true;

    return false;
}

bool StructureVariableSectionWall::IsParameterModifiable(int paramDefId) const
{
    if (!GetBaseData__()->IsParameterModifiable(paramDefId))
        return false;
    return true;
}

void StructureVariableSectionWall::Report(const ICopyContext & copyContext, ICopyStrategyReporter& reporter) const
{
    GetBaseData__()->Report(copyContext, reporter);
}

NdbObject* StructureVariableSectionWall::GetTopOwnerObject() const
{
    const StructureWall* pBaseData = GetBaseData__().get();
    if (!pBaseData)
        return nullptr;
    return pBaseData->GetTopOwnerObject();
}
